#ifndef _NE_ANY_H_
#define _NE_ANY_H_

#include <neinit.h>

namespace ne
{
    class Any
    {
        protected:
            class PlaceHolder
            {
                public:
                    virtual ~PlaceHolder() {}
                    virtual const std::type_info& type() const = 0;
                    virtual PlaceHolder* clone() const = 0;
            };

            template<typename ValueType>
            class Holder : public PlaceHolder
            {
                public:
                    explicit Holder(const ValueType &value)
                        : value(value)
                    {
                    }

                    virtual const std::type_info& type() const
                    {
                        return typeid(ValueType);
                    }

                    virtual PlaceHolder* clone() const
                    {
                        return new Holder(value);
                    }

                    virtual ~Holder() {}

                public:
                    ValueType value;
            };

        public:
            Any()
                : mpHolder(0)
            {
            }

            Any(const Any &a)
                : mpHolder(a.mpHolder ? a.mpHolder->clone() : 0)
            {
            }

            template<typename ValueType>
            explicit Any(const ValueType &value)
                : mpHolder(new Holder<ValueType>(value))
            {
            }

            Any& operator = (const Any &a)
            {
                Any(a).swap(*this);
                return *this;
            }

            template<typename ValueType>
            Any& operator = (const ValueType &value)
            {
                Any(value).swap(*this);
                return *this;
            }

            bool empty() const
            {
                return !mpHolder;
            }

            void clear()
            {
                delete mpHolder;
                mpHolder = 0;
            }

            const std::type_info& type() const
            {
                return mpHolder ? mpHolder->type() : typeid(void);
            }

            template<typename ValueType>
            ValueType value() const
            {
                assert(mpHolder);
                assert(type() == typeid(ValueType));
                return static_cast<Any::Holder<ValueType>*>(mpHolder)->value;
            }

            virtual Any& swap(Any &a)
            {
                std::swap(mpHolder, a.mpHolder);
                return *this;
            }

            virtual ~Any()
            {
                clear();
            }

        protected:
            template<typename ValueType>
            friend ValueType* any_cast(Any *);

        protected:
            PlaceHolder *mpHolder;
    };

    template<typename ValueType>
    ValueType* any_cast(Any *p)
    {
        if (p && p->type() == typeid(ValueType))
        {
            return &static_cast<Any::Holder<ValueType>*>(p->mpHolder)->value;
        }
        return 0;
    }

    template<typename ValueType>
    const ValueType* any_cast(const Any *p)
    {
        return any_cast<ValueType>(const_cast<Any*>(p));
    }

    template<typename ValueType>
    ValueType any_cast(const Any &a)
    {
        const ValueType *p = any_cast<ValueType>(&a);
        assert(p);
        return *p;
    }
}

#endif
